#include <GLee.h>
#include "GuiWidget.h"
#include "GuiContainer.h"
#include "FontManager.h"
#include <iostream>
#ifdef DEBUG_NEW
#include "debug/debug_new.h"
#endif

GuiProp::GuiProp():
        align(GUI_ALIGN_LEFT),
        valign(GUI_VALIGN_TOP),
        zindex(0.0f)
{
    for (int i=0;i<4;++i) {
        color[i] = 1.0f;
        bg_color[i] = 1.0f;
        padding[i] = 0;
    }
}

GuiDim::GuiDim():p(0.0f), a(0){}
GuiDim::GuiDim(float pc, int abs):p(pc), a(abs){}

GuiRect::GuiRect()
{
    validate();
}

GuiRect::GuiRect(float* p, int* a) {
    if (p) {
        _x.p = p[GUI_X];
        _y.p = p[GUI_Y];
        _w.p = p[GUI_W];
        _h.p = p[GUI_H];
    }
    if (a) {
        _x.a = a[GUI_X];
        _y.a = a[GUI_Y];
        _w.a = a[GUI_W];
        _h.a = a[GUI_H];
    }
    validate();
}

GuiRect::GuiRect(float xp, float yp, float wp, float hp) {
    _x.p = xp;
    _y.p = yp;
    _w.p = wp;
    _h.p = hp;
    validate();
}

GuiRect::GuiRect(int xa, int ya, int wa, int ha) {
    _x.a = xa;
    _y.a = ya;
    _w.a = wa;
    _h.a = ha;
    validate();
}

GuiRect::GuiRect(float xp, int xa, float yp, int ya, float wp, int wa, float hp, int ha) {
    _x.p = xp;
    _y.p = yp;
    _w.p = wp;
    _h.p = hp;
    _x.a = xa;
    _y.a = ya;
    _w.a = wa;
    _h.a = ha;
    validate();
}

GuiRect::~GuiRect() {

}

int* GuiRect::value() {
    return _val;
}

void GuiRect::validate(int x, int y, int w, int h) {
    _val[GUI_X] = (int)(_x.p * x) + _x.a + x;
    _val[GUI_Y] = (int)(_y.p * y) + _y.a + y;
    _val[GUI_W] = (int)(_w.p * w) + _w.a;
    _val[GUI_H] = (int)(_h.p * h) + _h.a;

    _val[GUI_R] = _val[GUI_X] + _val[GUI_W];
    _val[GUI_B] = _val[GUI_Y] + _val[GUI_H];
}

void GuiRect::validate(int v[]) {
    _val[GUI_X] = (int)(_x.p * v[GUI_X]) + _x.a + v[GUI_X];
    _val[GUI_Y] = (int)(_y.p * v[GUI_Y]) + _y.a + v[GUI_Y];
    _val[GUI_W] = (int)(_w.p * v[GUI_W]) + _w.a;
    _val[GUI_H] = (int)(_h.p * v[GUI_H]) + _h.a;

    _val[GUI_R] = _val[GUI_X] + _val[GUI_W];
    _val[GUI_B] = _val[GUI_Y] + _val[GUI_H];
}

GuiWidget::GuiWidget() {
    _texture = 0;
    _bg_texture = 0;
    _display = 0;
    _bg_display = 0;

    _max_x = 1.0f;
    _max_y = 1.0f;

    _parent = 0;

    _rect = new GuiRect();
    _prop = new GuiProp();
}

GuiWidget::GuiWidget(GuiRect* rect, GuiProp* prop, GLuint texture, GLuint bg_texture) {
    _texture = texture;
    _bg_texture = bg_texture;

    _display = 0;
    _bg_display = 0;

    _max_x = 1.0f;
    _max_y = 1.0f;

    _parent = 0;
    
    if (!rect) {
        _rect = new GuiRect();
    } else {
        _rect = rect;
    }
    if (!prop) {
        _prop = new GuiProp();
    } else {
        _prop = prop;
    }
}

GuiWidget::~GuiWidget() {
//    if (_texture != 0) {
//        glDeleteTextures(1, &_texture);
//    }
//    if (_bg_texture != 0) {
//        glDeleteTextures(1, &_bg_texture);
//    }
    if (_display != 0) {
        glDeleteLists(_display, 1);
    }
    if (_bg_display != 0) {
        glDeleteLists(_bg_display, 1);
    }
    delete _rect;
    delete _prop;
}

int GuiWidget::_next_p2(int p) {
    int rval = 1;
    while (rval < p) rval <<= 1;
    return rval;
}

GuiRect* GuiWidget::rect() {
    return _rect;
}

GuiProp* GuiWidget::prop() {
    return _prop;
}

//GLuint GuiWidget::texture() {
//    return _texture;
//}
//GLuint GuiWidget::bg_texture() {
//    return _bg_texture;
//}
//GLuint GuiWidget::display() {
//    return _display;
//}
//GLuint GuiWidget::bg_display() {
//    return _bg_display;
//}
//
//void GuiWidget::set_texture(GLuint t) {
//    _texture = t;
//}
//void GuiWidget::set_display(GLuint d) {
//    _display = d;
//}
//void GuiWidget::set_bg_texture(GLuint t) {
//    _bg_texture = t;
//}
//void GuiWidget::set_bg_display(GLuint d) {
//    _bg_display = d;
//}

void GuiWidget::set_parent(GuiContainer* parent) {
    _parent = parent;
    _rect->validate(_parent->rect()->value());
}

void GuiWidget::validate() {
    if (_parent) {
        _rect->validate(_parent->rect()->value());
    }
}
void GuiWidget::input(SDL_Event* evt, unsigned int ms){}
void GuiWidget::update(unsigned int ms){}
void GuiWidget::draw(FontManager* font)
{
    if (_bg_display == 0) {
        _build_bg_display(font);
    }
    if (_display == 0) {
        _build_display(font);
    }

    glPushMatrix();
    if (_bg_texture) glBindTexture(GL_TEXTURE_2D, _bg_texture);
    if (_bg_display) glCallList(_bg_display);
    if (_texture) glBindTexture(GL_TEXTURE_2D, _texture);
    if (_display) glCallList(_display);
    glPopMatrix();
}

void GuiWidget::redraw()
{
    if (_bg_display != 0) {
        glDeleteLists(_bg_display, 1);
    }
    if (_display != 0) {
        glDeleteLists(_display, 1);
    }
    _bg_display = 0;
    _display = 0;

    if (_parent != 0) {
        _parent->redraw();
    }
}

void GuiWidget::_build_bg_display(FontManager* font) {
    int* v = _rect->value();
    float z = _prop->zindex;
    if (_bg_texture == 0) {
        _bg_display = glGenLists(1);
        glNewList(_bg_display, GL_COMPILE);

        glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_LIGHTING);
        glColor4fv(_prop->bg_color);

        glBegin(GL_QUADS);

        glVertex3f(v[GUI_L], v[GUI_B], z);
        glVertex3f(v[GUI_R], v[GUI_B], z);
        glVertex3f(v[GUI_R], v[GUI_T], z);
        glVertex3f(v[GUI_L], v[GUI_T], z);

        glEnd();

        glPopAttrib();

        glEndList();
    } else {
        _bg_display = glGenLists(1);
        glNewList(_bg_display, GL_COMPILE);

        glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glColor4fv(_prop->bg_color);

        //glBindTexture(GL_TEXTURE_2D, _bg_texture);
        glBegin(GL_QUADS);

        glTexCoord2f(0.0f, 1.0f);
        glVertex3f(v[GUI_L], v[GUI_B], z);
        glTexCoord2f(1.0f, 1.0f);
        glVertex3f(v[GUI_R], v[GUI_B], z);
        glTexCoord2f(1.0f, 0.0f);
        glVertex3f(v[GUI_R], v[GUI_T], z);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3f(v[GUI_L], v[GUI_T], z);

        glEnd();
        glPopAttrib();
        glEndList();
    }
}

void GuiWidget::_build_display(FontManager* font) {
    int* v = _rect->value();
    int* p = _prop->padding;

    int t = v[GUI_T] + p[0];
    int r = v[GUI_R] - p[1];
    int b = v[GUI_B] - p[2];
    int l = v[GUI_L] + p[3];

    float z = _prop->zindex + 0.5;

    if (_texture == 0) {
        _display = glGenLists(1);
        glNewList(_display, GL_COMPILE);
        glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);

        glDisable(GL_TEXTURE_2D);
        glDisable(GL_LIGHTING);
        glColor4fv(_prop->color);

        glBegin(GL_QUADS);

        glVertex3f(l, b, z);
        glVertex3f(r, b, z);
        glVertex3f(r, t, z);
        glVertex3f(l, t, z);

        glEnd();
        glPopAttrib();
        glEndList();
    } else {
        _display = glGenLists(1);
        glNewList(_display, GL_COMPILE);

        glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glColor4fv(_prop->color);

        //glBindTexture(GL_TEXTURE_2D, _texture);
        glBegin(GL_QUADS);

        glTexCoord2f(0.0f, _max_y);
        glVertex3f(l, b, z);
        glTexCoord2f(_max_x, _max_y);
        glVertex3f(r, b, z);
        glTexCoord2f(_max_x, 0.0f);
        glVertex3f(r, t, z);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3f(l, t, z);

        glEnd();
        glPopAttrib();
        glEndList();
    }
}